#ifndef __MATCHER_H__
#define __MATCHER_H__
#include "../include/Frame.hpp"
#include "../include/MapPoint.hpp"
#include "../include/Converter.hpp"
using namespace std;
using namespace cv;
namespace ORBSLAM
{
    class Frame;
    class KeyFrame;
    class MapPoint;
    class Matcher
    {
    private:
        /* data */
        int mi_th_low;
        int mi_th_high;
        float mf_best_secondbest_ratio;
        bool mb_check_orientation;
        int mi_bin_len;

    public:
        Matcher(float ratio = 0.6, bool check_ori = true, int th_low = 50, int th_high = 100, int bin_len = 60);

        void Set_low_dist_th(int th);
        void Set_ratio(float ratio);
        void Set_if_check_orientation(bool b);
        void Set_bin_len(int bin_len);

        int Search_for_initialization(Frame &F1, Frame &F2, vector<Point2f> &vp_prematched, vector<int> &vn_matches12, int window_size, vector<pair<int, int>> &match_score);
        static int Compute_descriptor_distance(const Mat &descriptor1, const Mat &descriptor2);

        int Search_by_bow(KeyFrame *p_ref_KF, Frame &cur_frame, vector<MapPoint *> &vp_mpt_match);

        int Search_by_bow(KeyFrame *p_keyframe1, KeyFrame *p_keyframe2, vector<MapPoint *> &vp_match12);

        void Compute_three_maxima(vector<vector<int>> &histo, int histo_len, int &idx1, int &idx2, int &idx3);

        void Set_matcher_parameters(int th_low, int th_high, float best_second_ratio, bool check_orientation, int bin_len);

        int Search_by_projection(Frame &last_frme, Frame &cur_frame, const float th);

        int Search_by_projection_relocalization(Frame &cur_frame, KeyFrame *p_keyframe, const set<MapPoint *> &sp_already_found, float th, int orb_dist);

        int Search_by_projection(Frame &cur_frame, const vector<MapPoint *> &vp_local_mappoints, int search_radius, bool flag);

        int Search_by_projection(KeyFrame *p_keyframe, Mat mat_Scw, const vector<MapPoint *> &vp_mpt, const vector<KeyFrame *> &vp_mpt_keyframe, vector<MapPoint *> &vp_matched_mpt, vector<KeyFrame *> &vp_matched_keyframe, int th, float ratio_hamming);

        int Search_by_projection(KeyFrame *p_keyframe, Mat mat_Scw, const vector<MapPoint *> &vp_mpt, vector<MapPoint *> &vp_matched_mpt, int th, float ratio_hamming);

        int Search_for_triangulation(KeyFrame *p_keyframe1, KeyFrame *p_keyframe2, Matx33f F12, vector<pair<int, int>> &v_match_idx, const bool b_only_stereo, const bool b_coarse);

        bool Epipolar_constrain(const KeyPoint &kp1, const KeyPoint &kp2, Matx33f &F12, const float sigmalevel, const float unc);

        int Fuse(KeyFrame *p_keyframe, const vector<MapPoint *> &vp_mpt, const float th = 3.0);
        int Fuse(KeyFrame* p_keyframe,Mat mat_Scw,const vector<MapPoint*> &vp_mpt,float th,vector<MapPoint*> &vp_replace_mpt);
    };

}
#endif // __MATCHER_H__